#include <stdio.h>
#include <modbus.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>
#include <sys/msg.h>
#include "cJSON.h"
#include <stdlib.h>
struct mb_node
{
    int key;        //唯一键值
    char name[128]; //数据点名称
    int type;       //数据点类型
    int addr;
};
union val_t {
    int b_val;   //bool类型存储空间
    int i_val;   //整形值存储空间
    float f_val; //浮点值存储空间
};

struct std_node
{
    int key;             //唯一键值
    int type;            //数据点类型
    int dev_type;        //数据点属于哪个设备，根据网关支持的设备自行定义
    union val_t old_val; //变化上报后需要更新旧值
    union val_t new_val; //从共享内存取出最新数据，放到new_val中
    int ret;             //默认为-1，采集成功后设置为0，采集失败再置-1
};
// struct mb_node_list
// {
//     struct mb_node node;
//     struct list_head list;
// };

modbus_t *mod;
uint16_t *p;

//创建结构体来接收所用到的key
struct mb_node Key_node;

void Switch(int key);
void Get();
void Edit();
void *Edit_t(void *arg)
{
    Edit();
    // Get();
}
void *Get_t(void *arg)
{
    // Edit();
    Get();
}
int main(int argc, char const *argv[])
{
    int number_key, number_data;

    //打开cJSON文件
    FILE *file = fopen("node.json", "r");
    if (file == NULL)
    {
        perror("open err");
        return -1;
    }
    char buf[2048] = {};

    //读取data.cjson文件
    if (fread(buf, 1, 2048, file) < 0)
    {
        perror("read err");
        return -1;
    }

    //把字符串转换成cJSON树
    cJSON *root = cJSON_Parse(buf);
    if (NULL == root)
    {
        perror("parse err\n");
        return -1;
    }

    //获得树干上modbus的子树叉
    cJSON *item = cJSON_GetObjectItem(root, "modbus");

    //从item上得到名为data的子节点
    cJSON *data = cJSON_GetObjectItem(item, "data");

    //获得树干上modbus的子树叉
    item = cJSON_GetObjectItem(root, "mb_dev");

    //获得点表中服务器的地址
    cJSON *IP = cJSON_GetObjectItem(item, "addr");

    //
    cJSON *Port = cJSON_GetObjectItem(item, "port");

    //以tcp方式创建modbus实例，并初始化
    mod = modbus_new_tcp(IP->valuestring, Port->valueint); //电脑ip
    if (NULL == mod)
    {
        perror("mod err");
        return -1;
    }
    //设置从机ID
    int modslave = modbus_set_slave(mod, 1);
    if (modslave != 0)
    {
        perror("slr");
        return -1;
    }

    //和从机连接
    int modconnect = modbus_connect(mod);
    if (modconnect != 0)
    {
        perror("slave2 err.");
        return -1;
    }

    //创建线程
    pthread_t tid1;
    if (pthread_create(&tid1, NULL, Edit_t, NULL))
    {
        perror("create err");
        return -1;
    }
    //创建线程
    pthread_t tid2;
    if (pthread_create(&tid2, NULL, Get_t, NULL))
    {
        perror("create err");
        return -1;
    }

    while (1)
    {
        char input[128];
        scanf("%s", input);
        //input必须是"data1=1data2=6"类似的格式，注意前端过来的字符串会有双引号
        sscanf(input, "key=%d", &number_key);

        //首先获取data数组项数
        int size = cJSON_GetArraySize(data);
        for (size_t i = 0; i < size; i++)
        {
            //取出每个数组的节点，并解析
            cJSON *tem = cJSON_GetArrayItem(data, i);
            if (cJSON_GetObjectItem(tem, "key")->valueint == number_key)
            {
                Key_node.key = cJSON_GetObjectItem(tem, "key")->valueint;
                strcpy(Key_node.name, cJSON_GetObjectItem(tem, "name")->valuestring);
                Key_node.addr = cJSON_GetObjectItem(tem, "addr")->valueint;
                Key_node.type = cJSON_GetObjectItem(tem, "type")->valueint;
            }
        }
        Switch(Key_node.key);
    }
    // 5.关闭套接字
    modbus_close(mod);
    // 6.释放实例
    modbus_free(mod);
    return 0;
}
void Switch(int key)
{
    uint8_t dest[32];
    if (key == 103) //空调开关 线圈寄存器 1
    {

        modbus_read_bits(mod, Key_node.addr - 1, 1, dest);
        if (dest[0] == 1)
        {
            modbus_write_bit(mod, Key_node.addr - 1, 0);
        }
        else
            modbus_write_bit(mod, Key_node.addr - 1, 1);
    }
    else if (key == 105) //灯开关 线圈寄存器 1
    {
        modbus_read_bits(mod, Key_node.addr - 1, 1, dest);
        if (dest[0] == 1)
            modbus_write_bit(mod, Key_node.addr - 1, 0);
        else
            modbus_write_bit(mod, Key_node.addr - 1, 1);
    }
}
void Get()
{
    while (1)
    {
        sleep(2);
        uint16_t dest[32];
        modbus_read_input_registers(mod, 0, 2, dest);    //0x04 输入寄存器只读
        float temperature = modbus_get_float_dcba(dest); //转成浮点型
        printf("温度：%.4f\n", temperature);
    }
}
void Edit() //修改甲醛和co2的含量
{
    while (1)
    {
        sleep(2);
        int i = rand() % 210;
        float s = i / 10000.00 + 0.05;
        uint16_t dest[2];
        modbus_set_float(s, dest);
        printf("甲醛：%f\n", s);
        modbus_write_registers(mod, 0, 2, dest); //修改甲醛

        i = rand() % 150;
        s = i / 10.00 + 30;
        modbus_set_float(s, dest);
        printf("二氧化碳：%f\n", s);
        modbus_write_registers(mod, 2, 2, dest); //修改二氧化碳
    }
}